iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0
生成式 AI

T 大使 AI 之旅系列 第 13

【Day 13】LangChain 怎麼 Chain?

  • 分享至 

  • xImage
  •  

前情提要

上一篇文章我們了解了是如何透過 LangChain 來使用語言模型,分享了三個語言模型分別是 Gemini、GPT-4o、台智雲的 FFM-Llama3。然後我發文後發現 Hugging Face 也整合進 LangChain 框架了,今天 (2024/08/17) 看版本才 0.0.3,應該算是比較新整合進 LangChain,所以我應該會另外找時間加在 【Day 12】LLMs 最佳拍檔 - LangChain 🦜️🔗 中~

https://ithelp.ithome.com.tw/upload/images/20240818/20168336aTIVLuC9Wn.jpg

LCEL (LangChain Expression Language)

LangChain 最大亮點就是可以將我們所想要的東西,根據流程一個個的透過所謂的 Chain 🔗 連接起來。這個 Chain 的動作就是 LangChain 最核心的框架,被叫做 LCEL (LangChain Expression Language)。那接下來就來看看如何將我們的東西一個個的 Chain 起來吧!

關於實戰模型

LangChain 框架實作中,因為只會有不同企業推出的模型名稱不同的問題,但其實後續的 Chain 的部分都是一樣的。所以模型我會以 台智雲的 LLama3-FFM 70B 來實作,然後另外兩個 GPT 和 Gemini 會使用註解的方式補充。

Template

我自己最主要會用到的只有三種(我看網路上別人分享也差不多),分別是 PromptTemplateChatPromptTemplate 還有 FewShotPromptTemplate,那下面將分別進行實戰!

PromptTemplate 實戰🔥

from langchain_core.prompts import PromptTemplate
from langchain_ffm import ChatFormosaFoundationModel
llm = ChatFormosaFoundationModel(model="ffm-llama3-70b-chat", temperature=0.01)
# from langchain_openai import ChatOpenAI
# llm = ChatOpenAI(model="gpt-4o", temperature=0)
# from langchain_google_genai import ChatGoogleGenerativeAI
# llm = ChatGoogleGenerativeAI(model="gemini-pro", temperature=0)

# 一個 input
template = "介紹{input}是誰?內容要包含他們成員、出道日期和最著名的一首歌。"
# 兩種寫法都可以
prompt = PromptTemplate.from_template(template)
prompt = PromptTemplate(input_variables=["input"], template=template)
# 使用 "|" 將 Prompt 和 Model Chain 起來
chain = prompt | llm
response = chain.invoke("Aespa")
print(response.content)

# 兩個 input
template = "{league}在{year}賽季的總冠軍是誰?"
# 兩種寫法都可以
prompt = PromptTemplate.from_template(template)
prompt = PromptTemplate(input_variables=["league", "year"], template=template)
# 使用 "|" 將 Prompt 和 Model Chain 起來
chain = prompt | llm
response = chain.invoke({"league" : "NBA", "year":"2020"})
print(f"\n兩個 input 的結果:{response.content}")

https://ithelp.ithome.com.tw/upload/images/20240817/20168336nIKxQrKJkG.png
程式碼結果探討 🧐:

  • 如果只有一個 input 可以不用輸入變數名稱,但兩個或兩個以上就需要!
  • PromptTemplate 有兩種寫法都適用喔~
  • 使用 "|" 將 Prompt 和 Model 鏈接起來,就是所謂的 Chain

ChatPromptTemplate 實戰🔥

  • 來看看 ChatPromptTemplate 的結構
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate
from langchain_core.messages import HumanMessage, AIMessage

prompt1 = ChatPromptTemplate.from_messages(
	[
		("system", "你是一位NBA的資深球迷,名字叫{name}"),
		("human", "你知道NBA在2020賽季的總冠軍是誰嗎?"),
		("ai", "洛杉磯湖人"),
		("human", "{user_input}"),
	]
)
prompt2 = ChatPromptTemplate.from_messages(
	[
		SystemMessagePromptTemplate.from_template("你是一位NBA的資深球迷,名字叫{name}"),
		HumanMessage(content="你知道NBA在2020賽季的總冠軍是誰嗎?"),
		AIMessage(content="洛杉磯湖人"),
		HumanMessagePromptTemplate.from_template("{user_input}"),
	]
)
messages1 = prompt1.format_messages(name="Sean", user_input="那2021賽季的呢?對了我還不知道你的名字,可以告訴我嗎?")
messages2 = prompt2.format_messages(name="Sean", user_input="那2021賽季的呢?對了我還不知道你的名字,可以告訴我嗎?")
print(messages1, '\n', messages2)

https://ithelp.ithome.com.tw/upload/images/20240817/20168336EbNhM00JEf.png
程式碼結果探討 🧐:

  • 可以看到兩種寫法有一樣的結果,第一種比較直覺很好理解。第二種 Prompt 的部分全部以 LangChain 的函數表示,可以看到如果有參數在句子中的話要使用 PromptTemplate,如果只是單純句子的話,就使用一般的 Message。就看個人喜歡哪種方式來寫這個 ChatPromptTemplate
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate
from langchain_core.messages import HumanMessage, AIMessage
from langchain_ffm import ChatFormosaFoundationModel
llm = ChatFormosaFoundationModel(model="ffm-llama3-70b-chat", temperature=0.01)
# from langchain_openai import ChatOpenAI
# llm = ChatOpenAI(model="gpt-4o", temperature=0)
# from langchain_google_genai import ChatGoogleGenerativeAI
# llm = ChatGoogleGenerativeAI(model="gemini-pro", temperature=0)
# 使用 ChatPromptTemplate 模塊
prompt = ChatPromptTemplate.from_messages(
	[
		SystemMessagePromptTemplate.from_template("你是一位NBA的資深球迷,名字叫{name}"),
		HumanMessage(content="你知道NBA在2020賽季的總冠軍是誰嗎?"),
		AIMessage(content="洛杉磯湖人"),
		HumanMessagePromptTemplate.from_template("{user_input}"),
	]
)
# 使用 "|" 將 Prompt 和 Model Chain 起來
chain = prompt | llm
response = chain.invoke({"name" : "Sean", "user_input" : "那2021賽季的呢?對了我還不知道你的名字,可以告訴我嗎?"})
print(response.content)

https://ithelp.ithome.com.tw/upload/images/20240817/20168336lO64n8dmJZ.png
程式碼結果探討 🧐:

  • 可以看到 ChatPromptTemplate 可以自己設定先前的對話內容,在提問時會自動將前面的部分考慮進去。範例中我僅提到 2021 賽季,AI 就根據前面對話知道我在問的是 NBA 的總冠軍
  • SystemPrompt 不一定要設定,但我自己是習慣會加上,根據個人習慣決定即可
  • 使用 "|" 將 Prompt 和 Model 鏈接起來,就是所謂的 Chain

FewShotPromptTemplate 實戰🔥

先解釋一下什麼是 Few Shot,他是類似於 Zero Shot 的東西。在 【Day 08】Hugging Face 文本生成實戰 我有提過 Zero Shot,AI 會根據交辦的任務自行產出我們要的結果,但是 Zero Shot 往往在過於複雜的任務中表現不佳,譬如說要求他進行一個數學的數列推理、或是中文錯字修正。那 Few Shot 其實意思差不多,但是我們給予 AI 少量的樣本提示,在提示中提供示範以引導模型實現更好的效能。所以簡單來說 Zero Shot 就是不給 AI 提示,給一個提示叫做 One Shot,給兩個叫 Two Shot,以此類推~

from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_ffm import ChatFormosaFoundationModel
llm = ChatFormosaFoundationModel(model="ffm-llama3-70b-chat", temperature=0.01)
# from langchain_openai import ChatOpenAI
# llm = ChatOpenAI(model="gpt-4o", temperature=0)
# from langchain_google_genai import ChatGoogleGenerativeAI
# llm = ChatGoogleGenerativeAI(model="gemini-pro", temperature=0)
# 設定欲修正的詞 -> 現金餘額
text = "現金允額"
# zero-shot 的 prompt
template = """糾正以下文字的錯字 : {input}
修正結果 : """
prompt = PromptTemplate(input_variables=["input"], template=template)
# 使用 "|" 將 Prompt 和 Model Chain 起來
chain = prompt | llm
response = chain.invoke({"input":text})
print(f"Zero Shot 的結果\n欲修正內容 : {text}\n修正結果 : {response.content}")

# few-shot 的 prompt
template = """修正以下文字的錯字 : {input}
修正結果 : {answer}"""
example_prompt = PromptTemplate(input_variables=["input", "answer"], template=template)
# 根據上面 Prompt 的參數設定給 AI 的 few-shot
examples = [
	{
		"input": "通貨紅脹",
		"answer": "通貨膨脹"
	},
	{
		"input": "政府有一個獎注的補助費用",
		"answer": "政府有一個獎助的補助費用"
	},
	{
		"input": "庫藏骨",
		"answer": "庫藏股"
	},
]
# 使用 FewShotPromptTemplate 模塊
prompt = FewShotPromptTemplate(
	examples=examples,
	example_prompt=example_prompt,
	suffix="修正以下文字的錯字 : {input}",
	input_variables=["input"],
)
# 使用 "|" 將 Prompt 和 Model Chain 起來
chain = prompt | llm
response = chain.invoke({"input":text})
print(f'\nFew Shot 的結果\n欲修正內容 : {text}\n修正結果 : {response.content}')

https://ithelp.ithome.com.tw/upload/images/20240817/20168336GZodmVuB3N.png
程式碼結果探討 🧐:

  • 可以看到有給提示,AI 就有將錯字修正成我們要的結果,但是沒有提示的就沒有正確修正過來。
  • 設定給 AI 提示的變數要符合我們設計的 ExampleTemplate (範例),並且以 Json 型態表示
  • FewShotPromptTemplate 的參數中,有 提示內容(examples)範例模塊(example_prompt),那麼 suffix 是為模型提供最終的輸入提示,模型接著會根據這個新輸入來生成回應。以我這個例子來說就是最後會給 AI:修正以下文字的錯字 : 現金允額,AI 會參考前面提示然後根據這個最後提示最修正。

結論

我們使用最常被使用到的幾個 Template,在 LangChain 架構下可以更方便的去跟 AI 互動。那大家應該有發現,將 Prompt 和 Model 鏈接起來都是透過 "|" 這個符號,在 LangChain 中他就是將各種元件 Chain 起來的。那如果你跟我一樣常常忘記 Chain 的順序應該怎麼放,譬如說為什麼先放 Prompt 再放 Model,那你可以思考看看我們一般使用模型時是會先下 Prompt,才會經過模型。所以先開始的動作,那就會在前面。如果 Chain 的東西越來越多,才不會因此而忘記順序!

題外話🤣

今天回來屏東阿嬤家幫阿公阿嬤調整家裡的擺設,結果因為家具老舊的關係都很不好搬。結果沒想到鄰居都超熱心,有的主動來幫忙,有的直接送我們需要汰換的東西,還有幫我們處理冷氣、熱水管線的。果然熱心助人的人情味是台灣最美的風景😍
(明天要去東港吃爆生魚片!!)

下一篇文章:我要 Chain 好 Chain 滿!


上一篇
【Day 12】LLMs 最佳拍檔 - LangChain 🦜️🔗
下一篇
【Day 14】我要 Chain 好 Chain 滿!
系列文
T 大使 AI 之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言